package com.example.testapp.domain.manager

import android.content.Context
import android.util.Log
import androidx.annotation.NonNull
import androidx.work.Data
import androidx.work.Worker
import androidx.work.WorkerParameters
import com.example.testapp.data.AppDatabase
import com.example.testapp.data.dao.BalanceDao
import com.example.testapp.data.dao.BalanceImageDao
import com.example.testapp.data.dao.BalanceProcessRecordDao
import com.example.testapp.data.entity.Balance
import com.example.testapp.data.entity.BalanceImage
import com.example.testapp.data.entity.BalanceProcessRecord
import com.example.testapp.domain.util.ImageProcessUtil
import com.example.testapp.domain.util.ImageStorageUtil
import java.time.Duration
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicBoolean

/**
 * 账单图片处理工作类
 */
class BalanceImageProcessWorker(@NonNull context: Context, @NonNull workerParams: WorkerParameters) : 
    Worker(context, workerParams) {
    
    companion object {
        private const val TAG = "BalanceImageProcessWorker"

        // 输入参数键
        const val KEY_BALANCE_ID = "balance_id"
        const val KEY_IMAGE_ID = "image_id"
        const val KEY_PROCESS_RECORD_ID = "process_record_id"
        const val KEY_PROCESS_TYPE = "process_type"

        // 输出参数键
        const val KEY_RESULT_STATUS = "result_status"
        const val KEY_ERROR_CODE = "error_code"
        const val KEY_ERROR_MESSAGE = "error_message"
        const val KEY_PROCESS_TIME = "process_time"
    }

    // DAO对象
    private val balanceDao: BalanceDao
    private val balanceImageDao: BalanceImageDao
    private val processRecordDao: BalanceProcessRecordDao

    init {
        val database = AppDatabase.getDatabase(context)
        balanceDao = database.balanceDao()
        balanceImageDao = database.balanceImageDao()
        processRecordDao = database.balanceProcessRecordDao()
    }

    @NonNull
    override fun doWork(): Result {
        // 获取输入参数
        val balanceId = inputData.getLong(KEY_BALANCE_ID, 0)
        val imageId = inputData.getLong(KEY_IMAGE_ID, 0)
        val recordId = inputData.getLong(KEY_PROCESS_RECORD_ID, 0)
        val processType = inputData.getInt(KEY_PROCESS_TYPE, 0)

        if (balanceId == 0L || imageId == 0L || recordId == 0L || processType == 0) {
            Log.e(TAG, "Invalid input parameters")
            return Result.failure()
        }

        try {
            // 更新处理状态为"处理中"
            val startTime = LocalDateTime.now()
            processRecordDao.recordStart(recordId, startTime, BalanceProcessRecord.STATUS_PROCESSING, id.toString(), startTime)
            balanceDao.updateStatus(balanceId, Balance.STATUS_PROCESSING, startTime)
            
            return when (processType) {
                BalanceProcessRecord.PROCESS_TYPE_OCR -> processOcr(balanceId, imageId, recordId, startTime)
                BalanceProcessRecord.PROCESS_TYPE_IMAGE_STORAGE -> processImageStorage(balanceId, imageId, recordId, startTime)
                BalanceProcessRecord.PROCESS_TYPE_THUMBNAIL -> processThumbnail(balanceId, imageId, recordId, startTime)
                else -> {
                    Log.e(TAG, "Unsupported process type: $processType")
                    recordFailure(recordId, "UNSUPPORTED_TYPE", "Unsupported process type: $processType", startTime)
                    Result.failure()
                }
            }
        } catch (e: Exception) {
            Log.e(TAG, "Error processing image", e)
            try {
                recordFailure(recordId, "UNEXPECTED_ERROR", e.message ?: "Unknown error", LocalDateTime.now())
            } catch (ex: Exception) {
                Log.e(TAG, "Error recording failure", ex)
            }
            return Result.failure()
        }
    }

    /**
     * 处理OCR识别
     * @param balanceId 账单ID
     * @param imageId 图片ID
     * @param recordId 处理记录ID
     * @param startTime 开始时间
     * @return 处理结果
     */
    private fun processOcr(balanceId: Long, imageId: Long, recordId: Long, startTime: LocalDateTime): Result {
        // 获取图片实体
        val image = balanceImageDao.findById(imageId) ?: run {
            recordFailure(recordId, "IMAGE_NOT_FOUND", "Image not found: $imageId", startTime)
            return Result.failure()
        }

        // 处理OCR任务
        val latch = CountDownLatch(1)
        val success = AtomicBoolean(false)
        val errorCode = StringBuilder()
        val errorMessage = StringBuilder()

        ImageProcessUtil.processImage(applicationContext, image.getImagePath() ?: "", object : ImageProcessUtil.ImageProcessCallback {
            override fun onSuccess(result: ImageProcessUtil.OcrResult) {
                try {
                    // 更新账单信息
                    val balance = balanceDao.findById(balanceId)
                    balance?.let {
                        it.setAmount(result.amount)
                        it.setCategoryName(result.category)
                        it.setDescription(result.description)
                        // 将字符串日期转换为LocalDateTime
                        try {
                            val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd")
                            val billDate = LocalDateTime.parse(result.date, formatter)
                            it.setBillDate(billDate)
                        } catch (e: Exception) {
                            Log.e(TAG, "Error parsing date", e)
                            it.setBillDate(LocalDateTime.now())
                        }
                        
                        it.setStatus(Balance.STATUS_COMPLETED)
                        it.setUpdateDate(LocalDateTime.now())
                        balanceDao.update(it)
                    }

                    // 更新图片状态
                    val updateTime = LocalDateTime.now()
                    balanceImageDao.updateProcessStatus(imageId, true, BalanceImage.RECOGNITION_STATUS_SUCCESS, updateTime)

                    // 记录成功
                    recordSuccess(recordId, startTime)
                    success.set(true)
                } catch (e: Exception) {
                    Log.e(TAG, "Error updating database with OCR results", e)
                    errorCode.append("DATABASE_ERROR")
                    errorMessage.append(e.message)
                } finally {
                    latch.countDown()
                }
            }

            override fun onFailure(code: String, message: String) {
                errorCode.append(code)
                errorMessage.append(message)
                latch.countDown()
            }
        })

        try {
            // 等待OCR处理完成（最多等待30秒）
            latch.await(30, TimeUnit.SECONDS)
        } catch (e: InterruptedException) {
            Log.e(TAG, "OCR process interrupted", e)
            recordFailure(recordId, "PROCESS_INTERRUPTED", e.message ?: "Process interrupted", startTime)
            return Result.failure()
        }

        return if (success.get()) {
            Result.success()
        } else {
            recordFailure(recordId, errorCode.toString(), errorMessage.toString(), startTime)
            Result.failure()
        }
    }

    /**
     * 处理图片存储（将临时图片移动到永久存储）
     * @param balanceId 账单ID
     * @param imageId 图片ID
     * @param recordId 处理记录ID
     * @param startTime 开始时间
     * @return 处理结果
     */
    private fun processImageStorage(balanceId: Long, imageId: Long, recordId: Long, startTime: LocalDateTime): Result {
        try {
            // 获取图片实体
            val image = balanceImageDao.findById(imageId) ?: run {
                recordFailure(recordId, "IMAGE_NOT_FOUND", "Image not found: $imageId", startTime)
                return Result.failure()
            }

            // 移动到永久存储
            val permanentPath = ImageStorageUtil.moveToPermanentStorage(
                applicationContext,
                image.getImagePath() ?: "",
                balanceId
            ) ?: run {
                recordFailure(recordId, "STORAGE_ERROR", "Failed to move image to permanent storage", startTime)
                return Result.failure()
            }

            // 更新图片路径
            val updateTime = LocalDateTime.now()
            balanceImageDao.updateImagePath(imageId, permanentPath, updateTime)

            // 记录成功
            recordSuccess(recordId, startTime)
            return Result.success()
        } catch (e: Exception) {
            Log.e(TAG, "Error in image storage process", e)
            recordFailure(recordId, "STORAGE_PROCESS_ERROR", e.message ?: "Storage process error", startTime)
            return Result.failure()
        }
    }

    /**
     * 处理缩略图生成
     * @param balanceId 账单ID
     * @param imageId 图片ID
     * @param recordId 处理记录ID
     * @param startTime 开始时间
     * @return 处理结果
     */
    private fun processThumbnail(balanceId: Long, imageId: Long, recordId: Long, startTime: LocalDateTime): Result {
        try {
            // 获取图片实体
            val image = balanceImageDao.findById(imageId) ?: run {
                recordFailure(recordId, "IMAGE_NOT_FOUND", "Image not found: $imageId", startTime)
                return Result.failure()
            }

            // 生成缩略图
            val thumbnailPath = ImageStorageUtil.generateThumbnail(
                applicationContext,
                image.getImagePath() ?: "",
                balanceId
            ) ?: run {
                recordFailure(recordId, "THUMBNAIL_ERROR", "Failed to generate thumbnail", startTime)
                return Result.failure()
            }

            // 记录成功
            recordSuccess(recordId, startTime)
            return Result.success()
        } catch (e: Exception) {
            Log.e(TAG, "Error in thumbnail generation process", e)
            recordFailure(recordId, "THUMBNAIL_PROCESS_ERROR", e.message ?: "Thumbnail process error", startTime)
            return Result.failure()
        }
    }

    /**
     * 记录处理成功
     * @param recordId 处理记录ID
     * @param startTime 开始时间
     */
    private fun recordSuccess(recordId: Long, startTime: LocalDateTime) {
        val endTime = LocalDateTime.now()
        val timeConsumed = Duration.between(startTime, endTime).toMillis().toInt()
        processRecordDao.recordEnd(recordId, endTime, timeConsumed, BalanceProcessRecord.STATUS_COMPLETED, endTime)
    }

    /**
     * 记录处理失败
     * @param recordId 处理记录ID
     * @param errorCode 错误代码
     * @param errorMessage 错误信息
     * @param startTime 开始时间
     */
    private fun recordFailure(recordId: Long, errorCode: String, errorMessage: String, startTime: LocalDateTime) {
        val endTime = LocalDateTime.now()
        val timeConsumed = Duration.between(startTime, endTime).toMillis().toInt()
        
        processRecordDao.recordError(recordId, errorCode, errorMessage, "ERROR", endTime)
        processRecordDao.recordEnd(recordId, endTime, timeConsumed, BalanceProcessRecord.STATUS_FAILED, endTime)

        // 检查是否需要重试
        val record = processRecordDao.findById(recordId)
        if (record != null && record.getRetryCount() < record.getMaxRetryCount()) {
            // 计算下次重试时间（指数退避策略）
            val retryCount = record.getRetryCount() + 1
            // 退避时间：2^重试次数 * 1000毫秒（最少1秒，最多1小时）
            val backoffMillis = minOf(maxOf(1000, Math.pow(2.0, retryCount.toDouble()).toLong() * 1000), 3600000)
            val nextRetryTime = endTime.plusNanos(backoffMillis * 1000000)
            
            processRecordDao.updateRetryInfo(recordId, retryCount, nextRetryTime, endTime)
        }
    }
} 